package com.sz.biz.logistics.serialno.service.impl;

import com.sz.biz.logistics.serialno.constants.BillNumberConstants;
import com.sz.biz.logistics.serialno.dto.SerialNoRuleDetailDto;
import com.sz.biz.logistics.serialno.entity.SerialNoManagement;
import com.sz.biz.logistics.serialno.entity.SerialNoWarnNotice;
import com.sz.biz.logistics.serialno.service.NoJobService;
import com.sz.biz.logistics.serialno.service.NoManagementService;
import com.sz.biz.logistics.serialno.service.NoRuleService;
import com.sz.biz.logistics.serialno.service.NoWarnNoticeService;
import com.sz.common.base.cache.redis.RedisPoolManager;
import com.sz.common.base.dao.ParamData;
import com.sz.common.base.service.AbstractService;
import com.sz.common.base.utils.StringUtils;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import redis.clients.jedis.Jedis;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Function: TODO: ADD FUNCTION <br>
 * Author: Johnboy <br>
 * Date: 2017-12-22 12:42:00
 */
@Service
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public class NoJobServiceImpl extends AbstractService implements NoJobService {

    private final static String KEY="serialNumber";

    @Autowired
    private NoWarnNoticeService noWarnNoticeService;

    @Autowired
    @Lazy
    private NoRuleService noRuleService;

    @Autowired
    private NoManagementService generateChannelNo;

    @Autowired
    private SqlSessionTemplate sqlSessionTemplate;

    @Override
    @Async
    public void checkWarnNotice(SerialNoManagement channelNoManagement) {
        try {
            Thread.sleep(1000*20);
        } catch(InterruptedException e) {
            e.printStackTrace();
        }
        sqlSessionTemplate.clearCache();
        if(channelNoManagement==null){
            return;
        }
        Jedis jedis = RedisPoolManager.getJedis();
        if (jedis == null) {
            for(int i = 0; i < 3; i++) {
                jedis = RedisPoolManager.getJedis();
                if (jedis != null) {
                    break;
                }
                if (jedis == null) {
                    try {
                        Thread.sleep(300);
                    } catch(InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        if (jedis == null) {
            return;
        }
        SerialNoRuleDetailDto channelNoRule = noRuleService.queryDetailsDtoById(channelNoManagement.getRuleId());
        if (channelNoRule != null) {
            if(jedis.exists(channelNoRule.getId()+KEY)){
                return;
            }else{
                jedis.setnx(channelNoRule.getId()+KEY,channelNoRule.getNumberSection());
                jedis.expire(channelNoRule.getId()+KEY,60*10);
            }
            int currentRulesNoUsedTotal = getResidueNumberByServiceUidRuleIdAndBatchNo(channelNoRule.getId());
            //只有规则在启用状态下才会发出预警通知和阈值设置
            //低于报警阈值  就发出邮件/短信
            if (channelNoRule.getWarnThreshold() != null && currentRulesNoUsedTotal <= channelNoRule
                    .getWarnThreshold() && channelNoRule.getStatus() == BillNumberConstants.RuleStatus.ENABLED) {
                if (! StringUtils.isEmpty(channelNoRule.getReceiver())) {
                    SerialNoWarnNotice channelNoWarnNotice = noWarnNoticeService.queryByBatchNo
                            (channelNoManagement.getBatchNumber(), channelNoManagement.getRuleId(),
                                    channelNoManagement.getType());
                    if (channelNoWarnNotice == null) {
                        noRuleService.sendMessage(channelNoRule, channelNoManagement.getBatchNumber());
                    }
                }
            }

            if (channelNoRule.getStatus() == BillNumberConstants.RuleStatus.ENABLED && channelNoRule.getCreateMethod()
                    == BillNumberConstants.RuleCreateMethod.AUTO) {
                //低于阈值 就生成
                boolean flag = true;
                while(flag) {
                    if (currentRulesNoUsedTotal <= channelNoRule.getGenerateThreshold()) {
                        generateChannelNo.generateChannelNo(channelNoRule, BillNumberConstants.ChannelNoCreateMethod
                                .AUTO);
                        if (channelNoRule.getBatchNumber() != null && channelNoRule.getBatchNumber() > 0) {
                            currentRulesNoUsedTotal = currentRulesNoUsedTotal + channelNoRule.getBatchNumber();
                        }
                        else {
                            flag = false;
                        }
                    }
                    else {
                        flag = false;
                    }
                }
            }
            jedis.del(channelNoRule.getId()+KEY);
            jedis.close();
        }
    }

    @Override
    @Async
    public void batchCheckWarnNotice(List<SerialNoManagement> channelNoManagementList) {
        Map<Long,SerialNoManagement> managementMap = new HashMap<>(1);
        if (channelNoManagementList != null && channelNoManagementList.size() > 0) {
            //获取到规则的最后一个批次的单号
            for(SerialNoManagement channelNoManagement : channelNoManagementList) {
                if (! managementMap.containsKey(Long.valueOf(channelNoManagement.getId()))) {
                    managementMap.put(Long.valueOf(channelNoManagement.getRuleId()) , channelNoManagement);
                }
                else {
                    String batchNumber = managementMap.get(channelNoManagement.getId()).getBatchNumber();
                    if (batchNumber.compareTo(channelNoManagement.getBatchNumber()) < 0) {
                        managementMap.put(Long.valueOf(channelNoManagement.getRuleId()) , channelNoManagement);
                    }
                }
            }
        }
        managementMap.forEach((key,value)->{
            checkWarnNotice(value);
        });
    }

    public int getResidueNumberByServiceUidRuleIdAndBatchNo(Integer ruleId) {
        sqlSessionTemplate.clearCache();
        ParamData pd = new ParamData();
        if (ruleId != null && ruleId != 0) {
            pd.put("ruleId", ruleId);
        }
        return (int) dao.findForObject(getSqlName("findNoUsedNumberByRule"), pd);
    }

    public SerialNoManagement queryById(Long id){
        sqlSessionTemplate.clearCache();
        SerialNoManagement serialNoManagement = (SerialNoManagement) dao.findForObject(getSqlName("queryById"),id);
        return  serialNoManagement;
    }

    @Override
    protected String getMapperNamespace() {
        return "SerialNoManagementMapper";
    }
}
